Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to emit 'newContract' events #306

Merged
merged 4 commits into from
Jul 11, 2018

Conversation

mikeseese
Copy link
Contributor

This PR is in support of the new/upcoming Velma Solidity Debugger, which is a real-time (rather than trace analyzer) Solidity debugger with supported VS Code extension.

This PR introduces an option to the new VM() API called emitNewContractEvents (I am flexible with the name) which will emit an event named newContract (also open for name change) which provides a new contract's created address and it's deployment/creation bytecode (for reference/identification of the contract).

This event occurs immediately after the address is created for the new contract instance; this allows 3rd party libraries to know about the address before the constructor is executed. For example, this allows Velma to stop on breakpoints that are inside the constructor of a contract.

I am open for discussion about how this is to be implemented, but being able to know about the address prior to contract instance creation is necessary for Velma debugging (specifically for debugging constructors).

Let me know if you have any questions or comments! Thanks for the support!!

@coveralls
Copy link

coveralls commented Jun 24, 2018

Coverage Status

Coverage increased (+0.04%) to 85.739% when pulling fafd74c on SeesePlusPlus:emit-new-contract-event into 1394a2e on ethereumjs:master.

@holgerd77
Copy link
Member

Hi @seesemichaelj, thanks for the PR, looks really exciting what you are working on! I am generally positive towards this PR and my first impression is that both naming and implementation makes sense.

Want to dig a bit deeper though and also let this sink in for a few days. If someone else from the team (or actually anyone who has a look into this) have some comments, this would be also helpful!

Happy real-time debugging!
Holger

@mikeseese
Copy link
Contributor Author

Sounds great thanks!

@holgerd77
Copy link
Member

Hi @seesemichaelj, I now tested this locally within the run-transactions-complete example by adding an event listener to the index.js file like:

var vm = new VM({state: stateTrie, emitNewContractEvents: true })

//...

vm.on('newContract', function(object, callback) {
  console.log(object)
  callback()
})

This works and blocks when I remove the callback() execution. It doesn't block though when I remove the whole listener. I am not completely understanding why, is this intended behavior respectively can you explain that (so if I completely remove the code from above, the example script runs to the end again)?

Two thoughs on this, still thinking about the API:
a) if it doesn't block when not used and if this is intended: is it really necessary to make this event an option in the VM initialization or couldn't this just be emitted by default?
b) if we keep the option: would it make sense, to make the API on this more general and from the start create a structure where further events can easily be added, e.g. by doing a more generic API option opts.activatedEventList (or similar) and instantiate with e.g. { activatedEventList: ['newContract'] }?

@mikeseese
Copy link
Contributor Author

Thanks @holgerd77 for looking into this!

Before responding, I'm going to look into a couple of things. I think I may have misunderstood some things during implementation.

It definitely was intended to block. However a cleaner solution would be "only block if someone is listening on that topic."

I'll get back to you once I gather some more information on this.

@holgerd77
Copy link
Member

This is actually really strange: if I comment out callback() in the event listener it stops. If I am removing the complete event listener, it goes on again. Would a bit assume that there is some Node-internal stuff going on here, some kind of implicit/hidden (and maybe? accidental) callback execution?

Anyway: I think we can't (can we?) really trust this stuff. This actually would be somewhat our desired behavior, but I am not feeling really save on this.

@holgerd77
Copy link
Member

Here is the Node source code:
https://github.com/nodejs/node-v8/blob/canary/lib/events.js#L140

Not sure how deep one want to dig into that.

@mikeseese
Copy link
Contributor Author

mikeseese commented Jul 5, 2018

@holgerd77 Eek! My code is written for normal EventEmitter's, but apparently ethereumjs-vm uses https://github.com/ahultgren/async-eventemitter. And the first bullet on the readme:

Data sent to event listeners (eg emit(data)) must always be zero or one argument, and can not be a function.

and the second bullet:

The second argument can only be a callback, and will only be supplied if the event listener has an arity of two or more (eg function(e, next){}).

and my code:

self.emit('newContract', {
  address: createdAddress,
  code: code
}, callback)

😁

I'm going to fix this and get back to you when it's ready for review

@mikeseese mikeseese changed the title Add option to emit 'newContract' events [WIP] Add option to emit 'newContract' events Jul 5, 2018
@mikeseese
Copy link
Contributor Author

Ok @holgerd77 I have more information now!

  • Turns out the emitNewContractEvents option is not necessary. The AsyncEventEmitter library (https://github.com/ahultgren/async-eventemitter/blob/master/lib/AsyncEventEmitter.js#L19 is the emit function) will:
    • Call the callback if there are no listeners
    • For every listener, it will check the arity; if it is less than 2 (aka it doesn't have the callback as an argument to it's listener function), it just moves along as if it was a synchronous function
    • After all the listeners call the callback or, if an arity of <2, finish synchronous execution, the emit's callback will be called

As far as your comment: if I comment out callback() in the event listener it stops, I'm really confused what's going on with this. I thought I had a handle on it, but after more thinking, I'm more confused haha.

If I add a setInterval(() => {}, 500) to the bottom of the file, but have the callback() commented out (but still specified in the callback function args), then the program doesn't exit. This makes me think the AsyncEventEmitter isn't causing it to exit prematurely.

Without the setInterval I checked that the exit code is 0 so it's not error'ing out/crashing.

If I use a setTimeout(callback, 5000) instead of callback(), the program does wait and then carries on as expected. This makes me think that it's not the fact the function is stopping the program when it finishes it's synchronous execution.

I'm not really sure how to proceed on that front; changing it to the below still has the issue, so I don't believe this issue is related to this PR.

vm.on('step', function(object, callback) {
  console.log(object)
  //setTimeout(callback, 5000)
})
``

@mikeseese mikeseese changed the title [WIP] Add option to emit 'newContract' events Add option to emit 'newContract' events Jul 5, 2018
@mikeseese
Copy link
Contributor Author

I went ahead and removed the flag as it's not necessary per my prior comment. Let me know what you think about the other issue (that I think is unrelated), but as far as I'm concerned, this is now ready for re-review. Thanks!

Copy link
Member

@holgerd77 holgerd77 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, this works now, tested again locally. Will merge once this minor formatting thing is settled.

I can't promise for dedicated releases for a certain-party-feature-requests, but I will at least take this into account. Do you need this urgently to be released or does this have some time?

README.md Outdated
@@ -52,6 +52,7 @@ To build for standalone use in the browser, install `browserify` and check [run-
- [`vm.generateGenesis(cb)`](#vmgenerategenesiscb)
- [`VM` debugging hooks](#vm-debugging-hooks)
- [`vm.onStep`](#vmonstep)
- [`newContract` event](#newcontract)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reasons for the inconsistent naming in regards to the vm.onStep event description title?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I've disagreed with vm.onStep as it's not a function, so I named it something I felt was more intuitive without changing more than was my realm.

I can make it however you want. vm.onNewContractEvent to me is just incorrect.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can also change the title for the onStep event to your format, main thing is in my opinion that it is somewhat consistent.

this update makes the 'events' documentation consistent, accurate,
and all-inclusive
@mikeseese
Copy link
Contributor Author

@holgerd77 I went ahead and updated the section to be consistent and accurate. Looks like it was missing some extra events in the table of contents part, so I added those as well. Let me know if there are any other requested changes. Thanks!

@holgerd77
Copy link
Member

@seesemichaelj Thanks, cool, didn't want to be to picky on this - think our README also has other constistency lacks - but this just caught the eye so directly. 😄

Copy link
Member

@holgerd77 holgerd77 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, thanks, will merge now. Any comment on the release urgency?

@holgerd77 holgerd77 merged commit 4ecae8a into ethereumjs:master Jul 11, 2018
@mikeseese mikeseese deleted the emit-new-contract-event branch July 11, 2018 07:46
@mikeseese
Copy link
Contributor Author

Not urgent. I have one more PR coming to support Velma completely, so I won't be using the official ethereumjs-vm module until that's incorporated as well. From my perspective, you could wait until after that!

I should have that PR posted in the next day or two.

@holgerd77
Copy link
Member

Ok.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants